// Decompiled on 周六 2月 22 19:31:49 CST 2025 with Zomboid Decompiler v0.1.3 using Vineflower.
package zombie.core.backup;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.compress.archivers.zip.ParallelScatterZipCreator;
import org.apache.commons.compress.archivers.zip.Zip64Mode;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.compress.parallel.InputStreamSupplier;
import zombie.core.Core;
import zombie.debug.DebugLog;
import zombie.iso.IsoChunk;
import zombie.network.CoopSlave;
import zombie.network.GameServer;
import zombie.network.ServerOptions;

public class ZipBackup {
    private static final int compressionMethod = 0;
    static ParallelScatterZipCreator scatterZipCreator = null;
    private static long lastBackupTime = 0L;

    public static void onStartup() {
        lastBackupTime = System.currentTimeMillis();
        if (ServerOptions.getInstance().BackupsOnStart.getValue()) {
            makeBackupFile(GameServer.ServerName, ZipBackup.BackupTypes.startup);
        }
    }

    public static void onVersion() {
        if (ServerOptions.getInstance().BackupsOnVersionChange.getValue()) {
            String string0 = zombie.ZomboidFileSystem.instance.getCacheDir() + File.separator + "backups" + File.separator + "last_server_version.txt";
            String string1 = getStringFromZip(string0);
            String string2 = Core.getInstance().getGameVersion().toString();
            if (!string2.equals(string1)) {
                putTextFile(string0, string2);
                makeBackupFile(GameServer.ServerName, ZipBackup.BackupTypes.version);
            }
        }
    }

    public static void onPeriod() {
        int _int = ServerOptions.getInstance().BackupsPeriod.getValue();
        if (_int > 0) {
            if (System.currentTimeMillis() - lastBackupTime > (long)(_int * 60000)) {
                lastBackupTime = System.currentTimeMillis();
                makeBackupFile(GameServer.ServerName, ZipBackup.BackupTypes.period);
            }
        }
    }

    public static void makeBackupFile(String string2, ZipBackup.BackupTypes backupTypes) {
        String string0 = zombie.ZomboidFileSystem.instance.getCacheDir() + File.separator + "backups" + File.separator + backupTypes.name();
        long _long = System.currentTimeMillis();
        DebugLog.log("Start making backup to: " + string0);
        scatterZipCreator = new ParallelScatterZipCreator();
        CoopSlave.status("UI_ServerStatus_CreateBackup");
        FileOutputStream fileOutputStream = null;
        ZipArchiveOutputStream zipArchiveOutputStream = null;

        try {
            File file0 = new File(string0);
            if (!file0.exists()) {
                file0.mkdirs();
            }

            rotateBackupFile(backupTypes);
            String string1 = string0 + File.separator + "backup_1.zip";

            try {
                Files.deleteIfExists(Paths.get(string1));
            } catch (IOException iOException0) {
                iOException0.printStackTrace();
            }

            File file1 = new File(string1);
            file1.delete();
            fileOutputStream = new FileOutputStream(file1);
            zipArchiveOutputStream = new ZipArchiveOutputStream(fileOutputStream);
            zipArchiveOutputStream.setUseZip64(Zip64Mode.AsNeeded);
            zipArchiveOutputStream.setMethod(0);
            zipArchiveOutputStream.setLevel(0);
            zipTextFile("readme.txt", getBackupReadme(string2));
            zipArchiveOutputStream.setComment(getBackupReadme(string2));
            zipFile("options.ini", "options.ini");
            zipFile("popman-options.ini", "popman-options.ini");
            zipFile("latestSave.ini", "latestSave.ini");
            zipFile("debug-options.ini", "debug-options.ini");
            zipFile("sounds.ini", "sounds.ini");
            zipFile("gamepadBinding.config", "gamepadBinding.config");
            zipDir("mods", "mods");
            zipDir("Lua", "Lua");
            zipDir("db", "db");
            zipDir("Server", "Server");
            synchronized (IsoChunk.WriteLock) {
                zipDir("Saves" + File.separator + "Multiplayer" + File.separator + string2, "Saves" + File.separator + "Multiplayer" + File.separator + string2);

                try {
                    scatterZipCreator.writeTo(zipArchiveOutputStream);
                    DebugLog.log(scatterZipCreator.getStatisticsMessage().toString());
                    zipArchiveOutputStream.close();
                    fileOutputStream.close();
                } catch (IOException iOException1) {
                    iOException1.printStackTrace();
                }
            }
        } catch (Exception exception) {
            exception.printStackTrace();
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException iOException2) {
                    iOException2.printStackTrace();
                }
            }
        }

        DebugLog.log("Backup made in " + (System.currentTimeMillis() - _long) + " ms");
    }

    private static void rotateBackupFile(ZipBackup.BackupTypes backupTypes) {
        int int0 = ServerOptions.getInstance().BackupsCount.getValue() - 1;
        if (int0 > 0) {
            Path path0 = Paths.get(
                zombie.ZomboidFileSystem.instance.getCacheDir()
                    + File.separator
                    + "backups"
                    + File.separator
                    + backupTypes
                    + File.separator
                    + "backup_"
                    + (int0 + 1)
                    + ".zip"
            );

            try {
                Files.deleteIfExists(path0);
            } catch (IOException iOException) {
                iOException.printStackTrace();
            }

            for (int int1 = int0; int1 > 0; int1--) {
                Path path1 = Paths.get(
                    zombie.ZomboidFileSystem.instance.getCacheDir()
                        + File.separator
                        + "backups"
                        + File.separator
                        + backupTypes
                        + File.separator
                        + "backup_"
                        + int1
                        + ".zip"
                );
                Path path2 = Paths.get(
                    zombie.ZomboidFileSystem.instance.getCacheDir()
                        + File.separator
                        + "backups"
                        + File.separator
                        + backupTypes
                        + File.separator
                        + "backup_"
                        + (int1 + 1)
                        + ".zip"
                );

                try {
                    Files.move(path1, path2);
                } catch (Exception exception) {
                }
            }
        }
    }

    private static String getBackupReadme(String string0) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z");
        Date date = new Date(System.currentTimeMillis());
        simpleDateFormat.format(date);
        int _int = getWorldVersion(string0);
        String string1 = "";
        if (_int == -2) {
            string1 = "World isn't exist";
        } else if (_int == -1) {
            string1 = "World version cannot be determined";
        } else {
            string1 = String.valueOf(_int);
        }

        return "Backup time: "
            + simpleDateFormat.format(date)
            + "\nServerName: "
            + string0
            + "\nCurrent server version:"
            + Core.getInstance().getGameVersion()
            + "\nCurrent world version:195\nWorld version in this backup is:"
            + string1;
    }

    private static int getWorldVersion(String string) {
        File file = new File(
            zombie.ZomboidFileSystem.instance.getSaveDir() + File.separator + "Multiplayer" + File.separator + string + File.separator + "map_t.bin"
        );
        if (file.exists()) {
            try {
                FileInputStream fileInputStream = new FileInputStream(file);

                int int0;
                label64: {
                    int int1;
                    try {
                        DataInputStream dataInputStream = new DataInputStream(fileInputStream);

                        label60: {
                            try {
                                byte byte0 = dataInputStream.readByte();
                                byte byte1 = dataInputStream.readByte();
                                byte byte2 = dataInputStream.readByte();
                                byte byte3 = dataInputStream.readByte();
                                if (byte0 != 71 || byte1 != 77 || byte2 != 84 || byte3 != 77) {
                                    int1 = -1;
                                    break label60;
                                }

                                int1 = dataInputStream.readInt();
                                int0 = int1;
                            } catch (Throwable throwable0) {
                                try {
                                    dataInputStream.close();
                                } catch (Throwable throwable1) {
                                    throwable0.addSuppressed(throwable1);
                                }

                                throw throwable0;
                            }

                            dataInputStream.close();
                            break label64;
                        }

                        dataInputStream.close();
                    } catch (Throwable throwable2) {
                        try {
                            fileInputStream.close();
                        } catch (Throwable throwable3) {
                            throwable2.addSuppressed(throwable3);
                        }

                        throw throwable2;
                    }

                    fileInputStream.close();
                    return int1;
                }

                fileInputStream.close();
                return int0;
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }

        return -2;
    }

    private static void putTextFile(String string0, String string1) {
        try {
            Path path = Paths.get(string0);
            Files.createDirectories(path.getParent());

            try {
                Files.delete(path);
            } catch (Exception exception0) {
            }

            Files.write(path, string1.getBytes(), new OpenOption[0]);
        } catch (Exception exception1) {
            exception1.printStackTrace();
        }
    }

    private static String getStringFromZip(String string1) {
        String string0 = null;

        try {
            Path path = Paths.get(string1);
            if (Files.exists(path, new LinkOption[0])) {
                List list = Files.readAllLines(path);
                string0 = (String)list.get(0);
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }

        return string0;
    }

    private static void zipTextFile(String string1, String string0) {
        InputStreamSupplier inputStreamSupplier = () -> new ByteArrayInputStream(string0.getBytes(StandardCharsets.UTF_8));
        ZipArchiveEntry zipArchiveEntry = new ZipArchiveEntry(string1);
        zipArchiveEntry.setMethod(0);
        scatterZipCreator.addArchiveEntry(zipArchiveEntry, inputStreamSupplier);
    }

    private static void zipFile(String string1, String string0) {
        Path path = Paths.get(zombie.ZomboidFileSystem.instance.getCacheDir() + File.separator + string0);
        if (Files.exists(path, new LinkOption[0])) {
            InputStreamSupplier inputStreamSupplier = () -> {
                InputStream inputStream = null;

                try {
                    inputStream = Files.newInputStream(path);
                } catch (IOException iOException) {
                    iOException.printStackTrace();
                }

                return inputStream;
            };
            ZipArchiveEntry zipArchiveEntry = new ZipArchiveEntry(string1);
            zipArchiveEntry.setMethod(0);
            scatterZipCreator.addArchiveEntry(zipArchiveEntry, inputStreamSupplier);
        }
    }

    private static void zipDir(String string2, String string0) {
        Path path = Paths.get(zombie.ZomboidFileSystem.instance.getCacheDir() + File.separator + string0);
        if (Files.exists(path, new LinkOption[0])) {
            try {
                File file0 = new File(zombie.ZomboidFileSystem.instance.getCacheDir() + File.separator + string0);
                if (file0.isDirectory()) {
                    Iterator iterator = Arrays.asList(file0.listFiles()).iterator();
                    int _int = file0.getAbsolutePath().length() + 1;

                    while (iterator.hasNext()) {
                        File file1 = (File)iterator.next();
                        if (!file1.isDirectory()) {
                            String string1 = file1.getAbsolutePath().substring(_int);
                            InputStreamSupplier inputStreamSupplier = () -> {
                                InputStream inputStream = null;

                                try {
                                    inputStream = Files.newInputStream(file1.toPath());
                                } catch (IOException iOException) {
                                    iOException.printStackTrace();
                                }

                                return inputStream;
                            };
                            ZipArchiveEntry zipArchiveEntry = new ZipArchiveEntry(string2 + File.separator + string1);
                            zipArchiveEntry.setMethod(0);
                            scatterZipCreator.addArchiveEntry(zipArchiveEntry, inputStreamSupplier);
                        }
                    }
                }
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }
    }

    private static enum BackupTypes {
        period,
        startup,
        version;
    }
}
